Recently, I’ve been a bit caught up in old Kung-Fu movies. Shorting any technical explorations, I have instead been diving head-first into any and all Netflix accessible martial arts materpiece from the 70’s and 80’s.
While I’ve definitely been enjoying the films, I realized recently that I had little context for the movies I was watching. I wondered if some films, like our latest favorite, Executioners from Shaolin could be enjoyed even more, with better understanding of the context in which these films exist in the Kung-Fu universe.
So, I began a data driven quest for truth and understanding (or at least a semi-interesting dataset to explore) of all Shaw Brothers Kung Fu movies ever made!
For those not dedicating some portion of their finite lives to these retro wonders, the Shaw Brothers Studio is the most famous (to me) Kung-Fu film producer of that time, or any other. Their memorable, if confusing, title screen is typically part of my movie watching experience.
I figured this company’s entire martial arts collection would provide for a consistent and through look at the genre. Fortunately, after a bit of searching I stumbled on what appears to be a comprehensive list of Shaw Brothers Films (well, actually I learned that Shaw Brothers Studios did a lot of dramas and other types of films as well, just less well known in the Western world). I decided pull down details for each of these movies from the amazingly useful Letterboxd movie-list-creation site to explore them in a data driven way to see what patterns could be discovered and what context I could learn from those patterns.
So here is a bit of data exploration fun. The analysis is in R, using tips and tricks from Hadley Wickham’s wonderful new Data Science in R book.
This analysis can also be found in R Notebook form, which includes the full code and graphs in an integrated format. And (spoilers!), the end Actor Collaboration Network code can be found on github.
library(ggthemes)
library(tidyjson)
library(tidyverse)
library(forcats)
source("v_theme.R")
Read in Data
First, we need to get the data somehow. Its in JSON format, so let’s read the JSON into a string.
filename = '../out/shaw.json'
shaw_json <- paste(readLines(filename), collapse="")
incomplete final line found on '../out/shaw.json'
Then use tidyjson to convert the nested form into a flat data frame (tibble) we can work with.
films <- shaw_json %>% as.tbl_json %>% gather_array %>%
spread_values(
title = jstring("title"),
director = jstring('director'),
year = jstring('year'),
avg_rating = jstring('avg_rating'),
watches = jstring("watches"),
likes = jstring("likes")
)
films %>% head(n = 5) %>% select(title, director, year)
The above table has a row for every film.
We can use tidyjson again to create a row for each actor, duplicating the film-specific data for each actor that had a part in it.
cast <- shaw_json %>% as.tbl_json %>% gather_array %>%
spread_values(
title = jstring("title"),
director = jstring('director'),
year = jstring('year'),
avg_rating = jstring('avg_rating'),
watches = jstring("watches"),
likes = jstring("likes")
) %>% enter_object("cast") %>% gather_array() %>%
spread_values(
name = jstring("name")
)
cast %>% head(n = 8) %>% select(title, year, name)
Right now characters are a separte array
characters <- shaw_json %>% as.tbl_json %>% gather_array %>%
spread_values(
title = jstring("title"),
director = jstring('director'),
year = jstring('year'),
avg_rating = jstring('avg_rating'),
watches = jstring("watches"),
likes = jstring("likes")
) %>% enter_object("characters") %>% gather_array() %>%
spread_values(
name = jstring("name")
)
Real quick, let’s get a sense of the number of films in our data.
nrow(films)
[1] 260
260! That’s a lot of Kung-Fu. Let’s take a look at these films from a few different angles. We can start with release year.
Shaw Brothers, Through The Ages
So, I said retro, when exactly were these movies made?
source("v_theme.R")
films %>% ggplot(aes(x = year)) +
geom_bar() +
labs(title = 'Shaw Bros Films by Year') +
#fte_theme()
theme_fivethirtyeight()

The first Kung-fu Shaw Brothers film in this data set is Temple of the Red Lotus from 1965. From the reviews, it sounds like it was a bit rough around the edges - but thats about what you would expect from this burgeoning genre.
The studio hits its stride in the early 70’s, with a lull in the mid 70’s and another spike in the late 70’s, early 80’s. Keep in mind that even during the lull, the studio is still putting out 10 or more Kung-fu movies most years.
Shaw Brothers Directorial Favorites
We have the director for each movie in our dataset, let’s look to see if there are any popular standouts.
by_director <- films %>% group_by(director) %>% summarise(n = n()) %>% arrange(-n)
by_director %>% filter(n > 1) %>%
ggplot(aes(x = fct_reorder(director, n), y = n)) +
geom_bar(stat = "identity") +
coord_flip() +
labs(title = 'Counts of Shaw Bros Films by Director') +
theme_fivethirtyeight()

I’d say! Chang Cheh directed 67 or roughly 26% of all Shaw Brothers Kung-fu!
According to his Wikipedia page, he was known as the “The Godfather of Hong Kong cinema”, and rightly so - at least in terms of quantity.
Let’s pull out the top 5 directors, in terms of movie count, and see when they were most active.
# pull out just the top 5 directors
top_directors <- by_director %>% head(n = 5)
# filter films to those directed by these titans of kung-fu
films_top_director <- films %>% filter(director %in% top_directors$director)
films_top_director %>%
ggplot(aes(x = year)) +
geom_bar(aes(fill = director)) +
labs(title = 'Shaw Bros Top Director Count by Year') +
theme_fivethirtyeight()

# Try Fill Position
films_top_director %>%
ggplot(aes(x = year)) +
geom_bar(aes(fill = director), position = "fill") +
labs(title = 'Shaw Bros Top Director Count by Year') +
theme_fivethirtyeight()

That was with filtering to just the top directors. What happens when we put all of them in?
films_top_director_all <- films %>% mutate(director_label = ifelse(director %in% top_directors$director, director, 'Other'))
films_top_director_all %>%
ggplot(aes(x = year)) +
geom_bar(aes(fill = director_label)) +
labs(title = 'Shaw Bros Director Count by Year', fill = '') +
theme_fivethirtyeight()

films_top_director_all %>%
ggplot(aes(x = year)) +
geom_bar(aes(fill = director_label), position = 'fill') +
labs(title = 'Shaw Bros Director Count by Year', fill = '') +
theme_fivethirtyeight()

Actor Troupes and Groups
Even with my novice-level consuption of Shaw Brothers films, one thing I noticed early on was a lot of familiar faces that showed up in many of the movies. My assumption is just like directors, there are a number of actors that are heavily reused in these films. Let’s see if I am right!
First, just like directors, we can look at counts by actor.
by_actor <- cast %>% group_by(name) %>% summarise(n = n()) %>% arrange(-n)
by_actor %>% filter(n > 15) %>%
ggplot(aes(x = fct_reorder(name, n), y = n)) +
geom_bar(stat = "identity") +
coord_flip() +
labs(title = 'Counts of Shaw Bros Films by Actor') +
theme_fivethirtyeight()

Wow! Ku Feng apparently appeared in 82 Kung-Fu movies. That’s a lot of Kung-Fu!
His Wikipedia page isn’t as impressed with this feat as I am, providing little information on this Martial Arts Maniac. Apparently his real name is Chan Sze-man, and his first film was in 1959, and apparently he is still acting. The HKMDB, or Hong Kong Movie Database, provides just a bit more info:
In 1965, Ku formally signed an acting contract with Shaw Brothers where he made around 100 films for them and became most notably known as one of their top character actors. He has worked with just about every top Hong Kong director in a variety of films.
Ok then, well props to you Ku.
Did most of the top actors’ carreers span multiple decades, or did actors come and go quickly? Let’s graph the top actor’s movie count by year.
top_actor <- by_actor %>% head(n = 16)
films_top_actor <- cast %>% filter(name %in% top_actor$name)
films_top_actor %>%
ggplot(aes(x = year, fill = name)) +
geom_bar() +
labs(title = 'Top Actors Film Count by Year') +
facet_wrap( ~ fct_relevel(name, top_actor$name)) +
# only label half of the years to make things a bit look cleaner
scale_x_discrete(labels = function(x) { return(ifelse(as.numeric(x) %% 2, x, '')) }) +
theme_fivethirtyeight() +
# angle label text
theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position="none")

Title Showdown
library(tidytext)
titles <- films %>% mutate(raw_title = title) %>% unnest_tokens(word, title)
titles_filter <- titles %>% anti_join(stop_words, by = "word")
by_word <- titles_filter %>% count(word, sort = TRUE)
by_word %>%
filter(n > 3) %>%
ggplot(aes(x = fct_reorder(word, n), y = n)) +
geom_bar(stat = 'identity') +
coord_flip() +
labs(title = 'Top Words Used in Kung-Fu Titles') +
theme_fivethirtyeight()

top_word <- by_word %>% head(n = 12)
films_top_word <- titles %>% filter(word %in% top_word$word)
films_top_word %>%
ggplot(aes(x = year, fill = word)) +
geom_bar() +
labs(title = 'Titles with Most Common Words by Year') +
facet_wrap( ~ fct_relevel(word, top_word$word)) +
scale_x_discrete(labels = function(x) { return(ifelse(as.numeric(x) %% 2, x, '')) }) +
theme_fivethirtyeight() +
theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position="none")

Swordsman or Shaolin?
top2_word <- by_word %>% head(n = 2)
films_top2_word <- titles %>% filter(word %in% top2_word$word)
films_top2_word %>%
ggplot(aes(x = year, fill = fct_inorder(word))) +
geom_bar() +
labs(title = 'Titles with Most Common Words by Year', fill = '') +
#scale_x_discrete(labels = function(x) { return(ifelse(as.numeric(x) %% 2, x, '')) }) +
theme_fivethirtyeight()

#theme(axis.text.x = element_text(angle = 45, hjust = 1))
Swordsman Titles
titles %>% filter(word == 'swordsman') %>% arrange(year) %>% select(raw_title, year)
swordsman success: https://en.wikipedia.org/wiki/One-Armed_Swordsman
It was the first of the new style of wuxia films emphasizing male anti-heroes, violent swordplay and heavy bloodletting. It was the first Hong Kong film to make HK$1 million at the local box office, propelling its star Jimmy Wang to super stardom.
Wuxia Films.
30 Essential Wuxia Films
The Chinese martial arts movie is generally split into two primary subgeneres: the kung fu film and the wuxia film. The kung fu film is newer and focuses primarily on hand-to-hand combat, it’s steeped in traditional fighting forms and there’s a general emphasis on the physical skill of the performer: special effects are generally disdained. Bruce Lee and Jackie Chan are its most famous practitioners and Lau Kar-leung its most important director.
Wuxia is a much older form, based ultimately in the long tradition of Chinese adventure literature, in classic novels such as The Water Margin or Journey to the West, or more contemporary works by authors like Louis Cha and Gu Long. Its heroes follow a very specific code of honor as they navigate the jianghu, an underworld of outlaws and bandits outside the normal streams of civilization.
From Wuxia Women Warriors
Less realistic than its cousin, the kung fu film, wuxia often includes gravity-defying stunts where legendary warriors fly through the air or punch holes straight through their enemies’ chests.
Shaolin Titles
titles %>% filter(word == 'shaolin') %>% arrange(year) %>% select(raw_title, year)
From History in the Shaw Brothers
These films, focused on the Shaolin Temple as a center for anti-Qing resistance, provide a dizzying metaphorical potential, with the Qing variously standing in for Western imperialists, the Japanese, the Nationalist Kuomingtang, the Communists, or even simply the Manchurians themselves, while the Buddhism of the monks allows for examining of the contradictions at the heart of traditional Chinese belief systems, between the imperatives of social justice and withdrawal from worldly concerns.
Finding A Mob of Venoms
Venom Mob
Inspiration from Love Actually Analysis by David Robinson.
Create a matrix of actor co-occurance.
summary(by_actor$n)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.000 2.000 4.572 4.000 82.000
library(reshape2)
# filter actors not in many movies
min_movie_actors <- by_actor %>% filter(n > 5)
popular_cast <- cast %>% filter(name %in% min_movie_actors$name)
cast_movie_matrix <- popular_cast %>%
acast(name ~ title, fun.aggregate = length)
Using name as value column: use value.var to override.
dim(cast_movie_matrix)
[1] 120 258
Rows are actors. Columns are movies.
Filter out movies with few co-occuring actors
cast_movie_df_filtered <- cast_movie_df %>% colSums(.)
norm <- cast_movie_matrix / rowSums(cast_movie_matrix)
hc_norm_cast <- hclust(dist(norm, method = "manhattan"))
Plot:
library(ggdendro)
ggdendrogram(hc_norm_cast, rotate = TRUE)

See ordering:
ordering <-hc_norm_cast$labels[hc_norm_cast$order]
ordering
[1] "Wong Ching-Ho" "Kara Hui" "Gordon Liu Chia-Hui" "Hsiao Ho"
[5] "Wilson Tong" "Lau Kar-Wing" "Liu Chia-Liang" "Chin Ping"
[9] "Jimmy Wang Yu" "Lisa Chiao Chiao" "Tien Feng" "Candy Wen Xue-Er"
[13] "Lung Tien-Hsiang" "Philip Kwok Chun-Fung" "Chiang Sheng" "Lu Feng"
[17] "Lo Meng" "Sun Chien" "Wong Lik" "Yu Tai-Ping"
[21] "Chin Siu-Ho" "Lam Chi-Tai" "Lau Fong-Sai" "Chiu Hung"
[25] "Wong Chung-Shun" "Tung Li" "Law Hon" "Lee Pang-Fei"
[29] "Chin Han" "Wang Ping" "Ou-Yang Sha-Fei" "Ivy Ling Po"
[33] "Lam Jing" "Chiang Nan" "Fung Ngai" "Fung Hak-On"
[37] "Lo Dik" "Chi Kuan-Chun" "Leung Kar-Yan" "Wang Han-Chen"
[41] "Choh Seung-Wan" "Helen Poon Bing-Seung" "Lee Hoi-Sang" "Phillip Ko Fei"
[45] "Wong Yu" "Chen Kuan-Tai" "Chiang Tao" "Chan Sze-Kai"
[49] "Yeung Jing-Jing" "Dang Wai-Ho" "Jason Pai Piao" "Kwan Fung"
[53] "Ng Hong-Sang" "Yuen Tak" "Lo Wei" "Chiu Sam-Yin"
[57] "Hung Lau" "Walter Tso Tat-Wah" "Austin Wai" "Wong Mei-Mei"
[61] "Keung Hon" "Lam Fai-Wong" "Alexander Fu Sheng" "Johnny Wang Lung-Wei"
[65] "Bruce Tong Yim-Chaan" "Dick Wei" "Tang Ching" "Wong Yung"
[69] "Cheng Pei-Pei" "Lan Wei-Lieh" "Cheng Lui" "Wang Kuang-Yu"
[73] "Chan Sing" "Lau Gong" "Cliff Lok" "Li Ching"
[77] "Shih Szu" "Wai Wang" "Chung Wa" "Teresa Ha Ping"
[81] "Bolo Yeung" "Tin Ching" "Chen Ping" "Danny Lee Sau-Yin"
[85] "Wong Chung" "Lau Wing" "Norman Chu" "Ku Kuan-Chung"
[89] "Ching Li" "Ngaai Fei" "Yuen Bun" "Yuen Wah"
[93] "Candice Yu On-On" "Derek Yee Tung-Sing" "Lau Wai-Ling" "Ling Yun"
[97] "Tung Lam" "Fan Mei-Sheng" "Lily Ho Li-Li" "Lily Li Li-Li"
[101] "David Chiang" "Ti Lung" "Lee Wan-Chung" "Chen Hung-Lieh"
[105] "Fang Mian" "Shu Pei-Pei" "Tang Ti" "Chang Yi"
[109] "Goo Man-Chung" "Shum Lo" "Wu Ma" "Cheung Pooi-Saan"
[113] "Dean Shek" "Chan Shen" "Wang Hsieh" "Ku Feng"
[117] "Lo Lieh" "Elliot Ngok" "Cheng Miu" "Yeung Chi-Hing"
ordered_films <- popular_cast %>% arrange(year) %>%
mutate(film_index = as.numeric(fct_inorder(factor(title))), cast_name = factor(name, levels = ordering))
ordered_films %>% ggplot(aes(film_index, cast_name)) +
geom_point() +
geom_path(aes(group = film_index))

# http://stackoverflow.com/questions/13281303/creating-co-occurrence-matrix
cooccur <- cast_movie_matrix %*% t(cast_movie_matrix)
diag(cooccur) <- 0
heatmap(cooccur, symm = TRUE )

cooccur is matrix with rows and columns as actors. The cells for each actor combo indicate the number of movies they have appeared together in.
summary(rowSums(cooccur))
Min. 1st Qu. Median Mean 3rd Qu. Max.
37.0 63.5 87.5 117.5 143.2 603.0
summary(colSums(cooccur))
Min. 1st Qu. Median Mean 3rd Qu. Max.
37.0 63.5 87.5 117.5 143.2 603.0
summary(colSums(cooccur != 0))
Min. 1st Qu. Median Mean 3rd Qu. Max.
16.00 34.75 45.00 47.55 54.00 110.00
collab_counts <- as.data.frame(colSums(cooccur != 0))
library(igraph)
cooccur <- cast_movie_matrix %*% t(cast_movie_matrix)
#cooccur <- ifelse(cooccur < 4, 0, cooccur)
g <- graph.adjacency(cooccur, weighted = TRUE, mode = "undirected", diag = FALSE)
summary(E(g)$weight)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.00 1.00 2.00 2.47 3.00 29.00
summary(degree(g))
Min. 1st Qu. Median Mean 3rd Qu. Max.
16.00 34.75 45.00 47.55 54.00 110.00
summary(strength(g))
Min. 1st Qu. Median Mean 3rd Qu. Max.
37.0 63.5 87.5 117.5 143.2 603.0
library(igraph)
cooccur <- cast_movie_matrix %*% t(cast_movie_matrix)
#cooccur <- ifelse(cooccur < 4, 0, cooccur)
g <- graph.adjacency(cooccur, weighted = TRUE, mode = "undirected", diag = FALSE)
low_degree_v <- V(g)[degree(g) < 10] #identify those vertices part of less than three edges
g <- delete_vertices(g, low_degree_v) #exclude them from the graph
low_weight_e <- E(g)[E(g)$weight < 3]
g <- delete_edges(g, low_weight_e)
low_strength_v <- V(g)[strength(g) < 90]
g <- delete_vertices(g, low_strength_v) #exclude them from the graph
V(g)$betweenness <- strength(g)
plot(g, edge.width = E(g)$weight,
#layout=layout.fruchterman.reingold,
layout=layout_with_fr,
vertex.label.dist=0.5,
#vertex.size = V(g)$betweenness,
vertex.size = 3,
vertex.color='steelblue',
vertex.frame.color='steelblue', #the color of the border of the dots
vertex.label.color='black', #the color of the name labels
vertex.label.font=2, #the font of the name labels
vertex.label.cex=1, #specifies the size of the font of the labels. can also be made to vary
edge.color = hsv(1,1,1,alpha=0.2)
)

chiang_sheng <- V(g)[V(g)$name == "Chiang Sheng"]
chiang_sheng_neighbors <- neighbors(g, chiang_sheng)
neighbor_edges <- incident_edges(g, chiang_sheng_neighbors)
sub_g <- make_empty_graph(n = length(chiang_sheng_neighbors), directed = FALSE)
add_vertices(sub_g, chiang_sheng_neighbors)
IGRAPH U--- 12 0 --
+ edges:
#add_edges(sub_g, neighbor_edges)
E(g)[neighbor_edges[1]]$color = hsv(0,0.2,0.5,alpha=0.5)
Error in structure(seq_along(x), names = names(x))[i] :
invalid subscript type 'list'
plot(g, edge.width = E(g)$weight,
#layout=layout.fruchterman.reingold,
layout=layout_with_fr,
vertex.label.dist=0.5,
#vertex.size = V(g)$betweenness,
vertex.size = 5,
vertex.color=V(g)$color,
vertex.frame.color='steelblue', #the color of the border of the dots
vertex.label.color='black', #the color of the name labels
vertex.label.font=2, #the font of the name labels
vertex.label.cex=1, #specifies the size of the font of the labels. can also be made to vary
edge.color = hsv(0,0.2,0.5,alpha=0.2)
)

cooccur_df <- data.frame(cooccur, col.names = colnames(cooccur))
cooccur_df$name <- row.names(cooccur)
cooccur_df <- cooccur_df %>% select(name, everything())
write_delim(cooccur_df, 'shaw_cooccurance.csv', delim = ';')
Other
R Markdown Notes
This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.
Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgU2hhdyBCcm90aGVycyBLdW5nIEZ1IEZpbG1zIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpSZWNlbnRseSwgSSd2ZSBiZWVuIGEgYml0IGNhdWdodCB1cCBpbiBvbGQgS3VuZy1GdSBtb3ZpZXMuIFNob3J0aW5nIGFueSB0ZWNobmljYWwgZXhwbG9yYXRpb25zLCBJIGhhdmUgaW5zdGVhZCBiZWVuIGRpdmluZyBoZWFkLWZpcnN0IGludG8gYW55IGFuZCBhbGwgTmV0ZmxpeCBhY2Nlc3NpYmxlIG1hcnRpYWwgYXJ0cyBtYXRlcnBpZWNlIGZyb20gdGhlIDcwJ3MgYW5kIDgwJ3MuIAoKV2hpbGUgSSd2ZSBkZWZpbml0ZWx5IGJlZW4gZW5qb3lpbmcgdGhlIGZpbG1zLCBJIHJlYWxpemVkIHJlY2VudGx5IHRoYXQgSSBoYWQgbGl0dGxlIGNvbnRleHQgZm9yIHRoZSBtb3ZpZXMgSSB3YXMgd2F0Y2hpbmcuIEkgd29uZGVyZWQgaWYgc29tZSBmaWxtcywgbGlrZSBvdXIgbGF0ZXN0IGZhdm9yaXRlLCBbRXhlY3V0aW9uZXJzIGZyb20gU2hhb2xpbl0oaHR0cDovL3d3dy5pbWRiLmNvbS90aXRsZS90dDAwNzYxNjgvKSBjb3VsZCBiZSBlbmpveWVkIGV2ZW4gbW9yZSwgd2l0aCBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgY29udGV4dCBpbiB3aGljaCB0aGVzZSBmaWxtcyBleGlzdCBpbiB0aGUgS3VuZy1GdSB1bml2ZXJzZS4gCgpTbywgSSBiZWdhbiBhIGRhdGEgZHJpdmVuIHF1ZXN0IGZvciB0cnV0aCBhbmQgdW5kZXJzdGFuZGluZyAob3IgYXQgbGVhc3QgYSBzZW1pLWludGVyZXN0aW5nIGRhdGFzZXQgdG8gZXhwbG9yZSkgb2YgYWxsIFNoYXcgQnJvdGhlcnMgS3VuZyBGdSBtb3ZpZXMgZXZlciBtYWRlIQoKRm9yIHRob3NlIG5vdCBkZWRpY2F0aW5nIHNvbWUgcG9ydGlvbiBvZiB0aGVpciBmaW5pdGUgbGl2ZXMgdG8gdGhlc2UgcmV0cm8gd29uZGVycywgdGhlIFtTaGF3IEJyb3RoZXJzIFN0dWRpb10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2hhd19Ccm90aGVyc19TdHVkaW8pIGlzIHRoZSBtb3N0IGZhbW91cyAodG8gbWUpIEt1bmctRnUgZmlsbSBwcm9kdWNlciBvZiB0aGF0IHRpbWUsIG9yIGFueSBvdGhlci4gVGhlaXIgbWVtb3JhYmxlLCBpZiBjb25mdXNpbmcsIHRpdGxlIHNjcmVlbiBpcyB0eXBpY2FsbHkgcGFydCBvZiBteSBtb3ZpZSB3YXRjaGluZyBleHBlcmllbmNlLiAgCgpJIGZpZ3VyZWQgdGhpcyBjb21wYW55J3MgZW50aXJlIG1hcnRpYWwgYXJ0cyBjb2xsZWN0aW9uIHdvdWxkIHByb3ZpZGUgZm9yIGEgY29uc2lzdGVudCBhbmQgdGhyb3VnaCBsb29rIGF0IHRoZSBnZW5yZS4gRm9ydHVuYXRlbHksIGFmdGVyIGEgW2JpdF0oKSBbb2ZdKCkgW3NlYXJjaGluZ10oKSBJIHN0dW1ibGVkIG9uIHdoYXQgYXBwZWFycyB0byBiZSBhIFtjb21wcmVoZW5zaXZlIGxpc3Qgb2YgU2hhdyBCcm90aGVycyBGaWxtc10oaHR0cHM6Ly9sZXR0ZXJib3hkLmNvbS9qZXdibzIzL2xpc3Qvc2hhdy1icm90aGVycy1tYXJ0aWFsLWFydHMtZmlsbXMvKSAod2VsbCwgYWN0dWFsbHkgSSBsZWFybmVkIHRoYXQgU2hhdyBCcm90aGVycyBTdHVkaW9zIGRpZCBhIGxvdCBvZiBkcmFtYXMgYW5kIG90aGVyIHR5cGVzIG9mIGZpbG1zIGFzIHdlbGwsIGp1c3QgbGVzcyB3ZWxsIGtub3duIGluIHRoZSBXZXN0ZXJuIHdvcmxkKS4gSSBkZWNpZGVkIFtwdWxsIGRvd24gZGV0YWlsc10oKSBmb3IgZWFjaCBvZiB0aGVzZSBtb3ZpZXMgZnJvbSB0aGUgYW1hemluZ2x5IHVzZWZ1bCBbTGV0dGVyYm94ZF0oaHR0cHM6Ly9sZXR0ZXJib3hkLmNvbS8pIG1vdmllLWxpc3QtY3JlYXRpb24gc2l0ZSB0byBleHBsb3JlIHRoZW0gaW4gYSBkYXRhIGRyaXZlbiB3YXkgdG8gc2VlIHdoYXQgcGF0dGVybnMgY291bGQgYmUgZGlzY292ZXJlZCBhbmQgd2hhdCBjb250ZXh0IEkgY291bGQgbGVhcm4gZnJvbSB0aG9zZSBwYXR0ZXJucy4KClNvIGhlcmUgaXMgYSBiaXQgb2YgZGF0YSBleHBsb3JhdGlvbiBmdW4uIFRoZSBhbmFseXNpcyBpcyBpbiBSLCB1c2luZyB0aXBzIGFuZCB0cmlja3MgZnJvbSBIYWRsZXkgV2lja2hhbSdzIHdvbmRlcmZ1bCBuZXcgW0RhdGEgU2NpZW5jZSBpbiBSXSgpIGJvb2suIAoKVGhpcyBhbmFseXNpcyBjYW4gYWxzbyBiZSBmb3VuZCBpbiBbUiBOb3RlYm9va10oKSBmb3JtLCB3aGljaCBpbmNsdWRlcyB0aGUgZnVsbCBjb2RlIGFuZCBncmFwaHMgaW4gYW4gaW50ZWdyYXRlZCBmb3JtYXQuIEFuZCAoc3BvaWxlcnMhKSwgdGhlIGVuZCBbQWN0b3IgQ29sbGFib3JhdGlvbiBOZXR3b3JrXSgpIGNvZGUgY2FuIGJlIFtmb3VuZCBvbiBnaXRodWJdKCkuIAoKYGBge3J9CmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkodGlkeWpzb24pCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGZvcmNhdHMpCgpzb3VyY2UoInZfdGhlbWUuUiIpCmBgYAoKIyMgUmVhZCBpbiBEYXRhCgpGaXJzdCwgd2UgbmVlZCB0byBnZXQgdGhlIGRhdGEgc29tZWhvdy4gSXRzIGluIEpTT04gZm9ybWF0LCBzbyBsZXQncyByZWFkIHRoZSBKU09OIGludG8gYSBzdHJpbmcuCgpgYGB7cn0KZmlsZW5hbWUgPSAnLi4vb3V0L3NoYXcuanNvbicKc2hhd19qc29uIDwtIHBhc3RlKHJlYWRMaW5lcyhmaWxlbmFtZSksIGNvbGxhcHNlPSIiKQpgYGAKClRoZW4gdXNlIFt0aWR5anNvbl0oaHR0cHM6Ly9naXRodWIuY29tL3NhaWx0aHJ1L3RpZHlqc29uKSB0byBjb252ZXJ0IHRoZSBuZXN0ZWQgZm9ybSBpbnRvIGEgZmxhdCBkYXRhIGZyYW1lIChbdGliYmxlXShodHRwczovL2Jsb2cucnN0dWRpby5vcmcvMjAxNi8wMy8yNC90aWJibGUtMS0wLTAvKSkgd2UgY2FuIHdvcmsgd2l0aC4gCgpgYGB7cn0KZmlsbXMgPC0gc2hhd19qc29uICU+JSBhcy50YmxfanNvbiAlPiUgZ2F0aGVyX2FycmF5ICU+JQogIHNwcmVhZF92YWx1ZXMoCiAgICB0aXRsZSA9IGpzdHJpbmcoInRpdGxlIiksCiAgICBkaXJlY3RvciA9IGpzdHJpbmcoJ2RpcmVjdG9yJyksCiAgICB5ZWFyID0ganN0cmluZygneWVhcicpLAogICAgYXZnX3JhdGluZyA9IGpzdHJpbmcoJ2F2Z19yYXRpbmcnKSwKICAgIHdhdGNoZXMgPSBqc3RyaW5nKCJ3YXRjaGVzIiksCiAgICBsaWtlcyA9IGpzdHJpbmcoImxpa2VzIikKICApCgpmaWxtcyAlPiUgaGVhZChuID0gNSkgJT4lIHNlbGVjdCh0aXRsZSwgZGlyZWN0b3IsIHllYXIpCmBgYAoKVGhlIGFib3ZlIHRhYmxlIGhhcyBhIHJvdyBmb3IgZXZlcnkgZmlsbS4gCgpXZSBjYW4gdXNlIGB0aWR5anNvbmAgYWdhaW4gdG8gY3JlYXRlIGEgcm93IGZvciBlYWNoIGFjdG9yLCBkdXBsaWNhdGluZyB0aGUgZmlsbS1zcGVjaWZpYyBkYXRhIGZvciBlYWNoIGFjdG9yIHRoYXQgaGFkIGEgcGFydCBpbiBpdC4KCmBgYHtyfQpjYXN0IDwtIHNoYXdfanNvbiAgJT4lIGFzLnRibF9qc29uICAlPiUgZ2F0aGVyX2FycmF5ICU+JQogIHNwcmVhZF92YWx1ZXMoCiAgICB0aXRsZSA9IGpzdHJpbmcoInRpdGxlIiksCiAgICBkaXJlY3RvciA9IGpzdHJpbmcoJ2RpcmVjdG9yJyksCiAgICB5ZWFyID0ganN0cmluZygneWVhcicpLAogICAgYXZnX3JhdGluZyA9IGpzdHJpbmcoJ2F2Z19yYXRpbmcnKSwKICAgIHdhdGNoZXMgPSBqc3RyaW5nKCJ3YXRjaGVzIiksCiAgICBsaWtlcyA9IGpzdHJpbmcoImxpa2VzIikKICApICU+JSBlbnRlcl9vYmplY3QoImNhc3QiKSAlPiUgZ2F0aGVyX2FycmF5KCkgJT4lCiAgc3ByZWFkX3ZhbHVlcygKICAgIG5hbWUgPSBqc3RyaW5nKCJuYW1lIikKICApCgpjYXN0ICU+JSBoZWFkKG4gPSA4KSAlPiUgc2VsZWN0KHRpdGxlLCB5ZWFyLCBuYW1lKQpgYGAKClJpZ2h0IG5vdyBjaGFyYWN0ZXJzIGFyZSBhIHNlcGFydGUgYXJyYXkKCmBgYHtyfQpjaGFyYWN0ZXJzIDwtIHNoYXdfanNvbiAgJT4lIGFzLnRibF9qc29uICAlPiUgZ2F0aGVyX2FycmF5ICU+JQogIHNwcmVhZF92YWx1ZXMoCiAgICB0aXRsZSA9IGpzdHJpbmcoInRpdGxlIiksCiAgICBkaXJlY3RvciA9IGpzdHJpbmcoJ2RpcmVjdG9yJyksCiAgICB5ZWFyID0ganN0cmluZygneWVhcicpLAogICAgYXZnX3JhdGluZyA9IGpzdHJpbmcoJ2F2Z19yYXRpbmcnKSwKICAgIHdhdGNoZXMgPSBqc3RyaW5nKCJ3YXRjaGVzIiksCiAgICBsaWtlcyA9IGpzdHJpbmcoImxpa2VzIikKICApICU+JSBlbnRlcl9vYmplY3QoImNoYXJhY3RlcnMiKSAlPiUgZ2F0aGVyX2FycmF5KCkgJT4lCiAgc3ByZWFkX3ZhbHVlcygKICAgIG5hbWUgPSBqc3RyaW5nKCJuYW1lIikKICApCmBgYAoKUmVhbCBxdWljaywgbGV0J3MgZ2V0IGEgc2Vuc2Ugb2YgdGhlIG51bWJlciBvZiBmaWxtcyBpbiBvdXIgZGF0YS4KCmBgYHtyfQpucm93KGZpbG1zKQpgYGAKCjI2MCEgVGhhdCdzIGEgbG90IG9mIEt1bmctRnUuIExldCdzIHRha2UgYSBsb29rIGF0IHRoZXNlIGZpbG1zIGZyb20gYSBmZXcgZGlmZmVyZW50IGFuZ2xlcy4gV2UgY2FuIHN0YXJ0IHdpdGggcmVsZWFzZSB5ZWFyLgoKIyMjIFNoYXcgQnJvdGhlcnMsIFRocm91Z2ggVGhlIEFnZXMKClNvLCBJIHNhaWQgcmV0cm8sIHdoZW4gZXhhY3RseSB3ZXJlIHRoZXNlIG1vdmllcyBtYWRlPwoKYGBge3J9CnNvdXJjZSgidl90aGVtZS5SIikKZmlsbXMgJT4lIGdncGxvdChhZXMoeCA9IHllYXIpKSArCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgRmlsbXMgYnkgWWVhcicpICsgCiAgI2Z0ZV90aGVtZSgpCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKYGBgCgpUaGUgZmlyc3QgS3VuZy1mdSBTaGF3IEJyb3RoZXJzIGZpbG0gaW4gdGhpcyBkYXRhIHNldCBpcyBbVGVtcGxlIG9mIHRoZSBSZWQgTG90dXNdKGh0dHBzOi8vbGV0dGVyYm94ZC5jb20vZmlsbS90ZW1wbGUtb2YtdGhlLXJlZC1sb3R1cy8pIGZyb20gMTk2NS4gRnJvbSB0aGUgcmV2aWV3cywgaXQgc291bmRzIGxpa2UgaXQgd2FzIGEgYml0IHJvdWdoIGFyb3VuZCB0aGUgZWRnZXMgLSBidXQgdGhhdHMgYWJvdXQgd2hhdCB5b3Ugd291bGQgZXhwZWN0IGZyb20gdGhpcyBidXJnZW9uaW5nIGdlbnJlLgoKVGhlIHN0dWRpbyBoaXRzIGl0cyBzdHJpZGUgaW4gdGhlIGVhcmx5IDcwJ3MsIHdpdGggYSBsdWxsIGluIHRoZSBtaWQgNzAncyBhbmQgYW5vdGhlciBzcGlrZSBpbiB0aGUgbGF0ZSA3MCdzLCBlYXJseSA4MCdzLiBLZWVwIGluIG1pbmQgdGhhdCBldmVuIGR1cmluZyB0aGUgbHVsbCwgdGhlIHN0dWRpbyBpcyBfc3RpbGxfIHB1dHRpbmcgb3V0IDEwIG9yIG1vcmUgS3VuZy1mdSBtb3ZpZXMgbW9zdCB5ZWFycy4gCgoKIyMjIFNoYXcgQnJvdGhlcnMgRGlyZWN0b3JpYWwgRmF2b3JpdGVzCgpXZSBoYXZlIHRoZSBkaXJlY3RvciBmb3IgZWFjaCBtb3ZpZSBpbiBvdXIgZGF0YXNldCwgbGV0J3MgbG9vayB0byBzZWUgaWYgdGhlcmUgYXJlIGFueSBwb3B1bGFyIHN0YW5kb3V0cy4KCgpgYGB7cn0KYnlfZGlyZWN0b3IgPC0gZmlsbXMgJT4lIGdyb3VwX2J5KGRpcmVjdG9yKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBhcnJhbmdlKC1uKQoKICBieV9kaXJlY3RvciAlPiUgZmlsdGVyKG4gPiAxKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcihkaXJlY3RvciwgbiksIHkgPSBuKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICdDb3VudHMgb2YgU2hhdyBCcm9zIEZpbG1zIGJ5IERpcmVjdG9yJykgKwogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKSSdkIHNheSEgW0NoYW5nIENoZWhdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NoYW5nX0NoZWgpIGRpcmVjdGVkIDY3IG9yIHJvdWdobHkgMjYlIG9mIGFsbCBTaGF3IEJyb3RoZXJzIEt1bmctZnUhCgpBY2NvcmRpbmcgdG8gaGlzIFdpa2lwZWRpYSBwYWdlLCBoZSB3YXMga25vd24gYXMgdGhlICJUaGUgR29kZmF0aGVyIG9mIEhvbmcgS29uZyBjaW5lbWEiLCBhbmQgcmlnaHRseSBzbyAtIGF0IGxlYXN0IGluIHRlcm1zIG9mIHF1YW50aXR5LiAKCkxldCdzIHB1bGwgb3V0IHRoZSB0b3AgNSBkaXJlY3RvcnMsIGluIHRlcm1zIG9mIG1vdmllIGNvdW50LCBhbmQgc2VlIHdoZW4gdGhleSB3ZXJlIG1vc3QgYWN0aXZlLiAKCmBgYHtyfQoKIyBwdWxsIG91dCBqdXN0IHRoZSB0b3AgNSBkaXJlY3RvcnMKdG9wX2RpcmVjdG9ycyA8LSBieV9kaXJlY3RvciAlPiUgaGVhZChuID0gNSkKIyBmaWx0ZXIgZmlsbXMgdG8gdGhvc2UgZGlyZWN0ZWQgYnkgdGhlc2UgdGl0YW5zIG9mIGt1bmctZnUKZmlsbXNfdG9wX2RpcmVjdG9yIDwtIGZpbG1zICU+JSBmaWx0ZXIoZGlyZWN0b3IgJWluJSB0b3BfZGlyZWN0b3JzJGRpcmVjdG9yKQoKI3Bsb3QgYmFyIGNoYXJ0CmZpbG1zX3RvcF9kaXJlY3RvciAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyKSkgKwogIGdlb21fYmFyKGFlcyhmaWxsID0gZGlyZWN0b3IpKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgVG9wIERpcmVjdG9yIENvdW50IGJ5IFllYXInKSArIAogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKCmBgYHtyfQojIFRyeSBGaWxsIFBvc2l0aW9uCmZpbG1zX3RvcF9kaXJlY3RvciAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyKSkgKwogIGdlb21fYmFyKGFlcyhmaWxsID0gZGlyZWN0b3IpLCBwb3NpdGlvbiA9ICJmaWxsIikgKwogIGxhYnModGl0bGUgPSAnU2hhdyBCcm9zIFRvcCBEaXJlY3RvciBDb3VudCBieSBZZWFyJykgKyAKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQpgYGAKClRoYXQgd2FzIHdpdGggZmlsdGVyaW5nIHRvIF9qdXN0XyB0aGUgdG9wIGRpcmVjdG9ycy4gV2hhdCBoYXBwZW5zIHdoZW4gd2UgcHV0IGFsbCBvZiB0aGVtIGluPwoKYGBge3J9CmZpbG1zX3RvcF9kaXJlY3Rvcl9hbGwgPC0gZmlsbXMgJT4lIG11dGF0ZShkaXJlY3Rvcl9sYWJlbCA9IGlmZWxzZShkaXJlY3RvciAlaW4lIHRvcF9kaXJlY3RvcnMkZGlyZWN0b3IsIGRpcmVjdG9yLCAnT3RoZXInKSkKCmZpbG1zX3RvcF9kaXJlY3Rvcl9hbGwgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhcikpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IGRpcmVjdG9yX2xhYmVsKSkgKwogIGxhYnModGl0bGUgPSAnU2hhdyBCcm9zIERpcmVjdG9yIENvdW50IGJ5IFllYXInLCBmaWxsID0gJycpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKYGBgCgpgYGB7cn0KZmlsbXNfdG9wX2RpcmVjdG9yX2FsbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyKSkgKwogIGdlb21fYmFyKGFlcyhmaWxsID0gZGlyZWN0b3JfbGFiZWwpLCBwb3NpdGlvbiA9ICdmaWxsJykgKwogIGxhYnModGl0bGUgPSAnU2hhdyBCcm9zIERpcmVjdG9yIENvdW50IGJ5IFllYXInLCBmaWxsID0gJycpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKYGBgCgojIyBBY3RvciBUcm91cGVzIGFuZCBHcm91cHMKCkV2ZW4gd2l0aCBteSBub3ZpY2UtbGV2ZWwgY29uc3VwdGlvbiBvZiBTaGF3IEJyb3RoZXJzIGZpbG1zLCBvbmUgdGhpbmcgSSBub3RpY2VkIGVhcmx5IG9uIHdhcyBhIGxvdCBvZiBmYW1pbGlhciBmYWNlcyB0aGF0IHNob3dlZCB1cCBpbiBtYW55IG9mIHRoZSBtb3ZpZXMuIE15IGFzc3VtcHRpb24gaXMganVzdCBsaWtlIGRpcmVjdG9ycywgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIGFjdG9ycyB0aGF0IGFyZSBoZWF2aWx5IHJldXNlZCBpbiB0aGVzZSBmaWxtcy4gTGV0J3Mgc2VlIGlmIEkgYW0gcmlnaHQhCgpGaXJzdCwganVzdCBsaWtlIGRpcmVjdG9ycywgd2UgY2FuIGxvb2sgYXQgY291bnRzIGJ5IGFjdG9yLiAKCmBgYHtyIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSA0fQpieV9hY3RvciA8LSBjYXN0ICU+JSBncm91cF9ieShuYW1lKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBhcnJhbmdlKC1uKQoKYnlfYWN0b3IgJT4lIGZpbHRlcihuID4gMTUpICU+JQogIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyKG5hbWUsIG4pLCB5ID0gbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICdDb3VudHMgb2YgU2hhdyBCcm9zIEZpbG1zIGJ5IEFjdG9yJykgKwogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKV293ISBbS3UgRmVuZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvS3VfRmVuZykgYXBwYXJlbnRseSBhcHBlYXJlZCBpbiA4MiBLdW5nLUZ1IG1vdmllcy4gVGhhdCdzIGEgbG90IG9mIEt1bmctRnUhCgpIaXMgV2lraXBlZGlhIHBhZ2UgaXNuJ3QgYXMgaW1wcmVzc2VkIHdpdGggdGhpcyBmZWF0IGFzIEkgYW0sIHByb3ZpZGluZyBsaXR0bGUgaW5mb3JtYXRpb24gb24gdGhpcyBNYXJ0aWFsIEFydHMgTWFuaWFjLiBBcHBhcmVudGx5IGhpcyByZWFsIG5hbWUgaXMgQ2hhbiBTemUtbWFuLCBhbmQgaGlzIGZpcnN0IGZpbG0gd2FzIGluIDE5NTksIGFuZCBhcHBhcmVudGx5IGhlIGlzIHN0aWxsIGFjdGluZy4gVGhlIFtIS01EQl0oaHR0cDovL2hrbWRiLmNvbS9kYi9wZW9wbGUvdmlldy5taHRtbD9pZD0zNTc5JmRpc3BsYXlfc2V0PWVuZyksIG9yIEhvbmcgS29uZyBNb3ZpZSBEYXRhYmFzZSwgcHJvdmlkZXMganVzdCBhIGJpdCBtb3JlIGluZm86Cgo+IEluIDE5NjUsIEt1IGZvcm1hbGx5IHNpZ25lZCBhbiBhY3RpbmcgY29udHJhY3Qgd2l0aCBTaGF3IEJyb3RoZXJzIHdoZXJlIGhlIG1hZGUgYXJvdW5kIDEwMCBmaWxtcyBmb3IgdGhlbSBhbmQgYmVjYW1lIG1vc3Qgbm90YWJseSBrbm93biBhcyBvbmUgb2YgdGhlaXIgdG9wIGNoYXJhY3RlciBhY3RvcnMuIEhlIGhhcyB3b3JrZWQgd2l0aCBqdXN0IGFib3V0IGV2ZXJ5IHRvcCBIb25nIEtvbmcgZGlyZWN0b3IgaW4gYSB2YXJpZXR5IG9mIGZpbG1zLgoKT2sgdGhlbiwgd2VsbCBwcm9wcyB0byB5b3UgS3UuCgpEaWQgbW9zdCBvZiB0aGUgdG9wIGFjdG9ycycgY2FycmVlcnMgc3BhbiBtdWx0aXBsZSBkZWNhZGVzLCBvciBkaWQgYWN0b3JzIGNvbWUgYW5kIGdvIHF1aWNrbHk/IExldCdzIGdyYXBoIHRoZSB0b3AgYWN0b3IncyBtb3ZpZSBjb3VudCBieSB5ZWFyLiAKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTV9CnRvcF9hY3RvciA8LSBieV9hY3RvciAlPiUgaGVhZChuID0gMTYpCmZpbG1zX3RvcF9hY3RvciA8LSBjYXN0ICU+JSBmaWx0ZXIobmFtZSAlaW4lIHRvcF9hY3RvciRuYW1lKQoKZmlsbXNfdG9wX2FjdG9yICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCBmaWxsID0gbmFtZSkpICsKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gJ1RvcCBBY3RvcnMgRmlsbSBDb3VudCBieSBZZWFyJykgKyAKICBmYWNldF93cmFwKCB+IGZjdF9yZWxldmVsKG5hbWUsIHRvcF9hY3RvciRuYW1lKSkgKwogICMgb25seSBsYWJlbCBoYWxmIG9mIHRoZSB5ZWFycyB0byBtYWtlIHRoaW5ncyBhIGJpdCBsb29rIGNsZWFuZXIKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHsgcmV0dXJuKGlmZWxzZShhcy5udW1lcmljKHgpICUlIDIsIHgsICcnKSkgfSkgKwogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpICsgCiAgIyBhbmdsZSBsYWJlbCB0ZXh0CiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgbGVnZW5kLnBvc2l0aW9uPSJub25lIikKCmBgYAoKCiMjIFRpdGxlIFNob3dkb3duCgpgYGB7cn0KbGlicmFyeSh0aWR5dGV4dCkKCmRhdGEoInN0b3Bfd29yZHMiKQpgYGAKCgpgYGB7cn0KdGl0bGVzIDwtIGZpbG1zICU+JSBtdXRhdGUocmF3X3RpdGxlID0gdGl0bGUpICU+JSB1bm5lc3RfdG9rZW5zKHdvcmQsIHRpdGxlKQpgYGAKCmBgYHtyfQp0aXRsZXNfZmlsdGVyIDwtIHRpdGxlcyAlPiUgYW50aV9qb2luKHN0b3Bfd29yZHMsIGJ5ID0gIndvcmQiKQpgYGAKCgpgYGB7cn0KYnlfd29yZCA8LSB0aXRsZXNfZmlsdGVyICU+JSBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKYnlfd29yZCAlPiUKICBmaWx0ZXIobiA+IDMpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcih3b3JkLCBuKSwgeSA9IG4pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpICsKICBjb29yZF9mbGlwKCkgKyAKICBsYWJzKHRpdGxlID0gJ1RvcCBXb3JkcyBVc2VkIGluIEt1bmctRnUgVGl0bGVzJykgKwogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKCmBgYHtyfQp0b3Bfd29yZCA8LSBieV93b3JkICU+JSBoZWFkKG4gPSAxMikKZmlsbXNfdG9wX3dvcmQgPC0gdGl0bGVzICU+JSBmaWx0ZXIod29yZCAlaW4lIHRvcF93b3JkJHdvcmQpCgpmaWxtc190b3Bfd29yZCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgZmlsbCA9IHdvcmQpKSArCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICdUaXRsZXMgd2l0aCBNb3N0IENvbW1vbiBXb3JkcyBieSBZZWFyJykgKyAKICBmYWNldF93cmFwKCB+IGZjdF9yZWxldmVsKHdvcmQsIHRvcF93b3JkJHdvcmQpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSB7IHJldHVybihpZmVsc2UoYXMubnVtZXJpYyh4KSAlJSAyLCB4LCAnJykpIH0pICsKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCgpgYGAKClN3b3Jkc21hbiBvciBTaGFvbGluPwoKYGBge3J9CnRvcDJfd29yZCA8LSBieV93b3JkICU+JSBoZWFkKG4gPSAyKQpmaWxtc190b3AyX3dvcmQgPC0gdGl0bGVzICU+JSBmaWx0ZXIod29yZCAlaW4lIHRvcDJfd29yZCR3b3JkKQoKZmlsbXNfdG9wMl93b3JkICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCBmaWxsID0gZmN0X2lub3JkZXIod29yZCkpKSArCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICdUaXRsZXMgd2l0aCBNb3N0IENvbW1vbiBXb3JkcyBieSBZZWFyJywgZmlsbCA9ICcnKSArIAogICNzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHsgcmV0dXJuKGlmZWxzZShhcy5udW1lcmljKHgpICUlIDIsIHgsICcnKSkgfSkgKwogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpIAogICN0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCioqU3dvcmRzbWFuIFRpdGxlcyoqCgpgYGB7cn0KdGl0bGVzICU+JSBmaWx0ZXIod29yZCA9PSAnc3dvcmRzbWFuJykgJT4lIGFycmFuZ2UoeWVhcikgJT4lIHNlbGVjdChyYXdfdGl0bGUsIHllYXIpCmBgYAoKc3dvcmRzbWFuIHN1Y2Nlc3M6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09uZS1Bcm1lZF9Td29yZHNtYW4KCj4gIEl0IHdhcyB0aGUgZmlyc3Qgb2YgdGhlIG5ldyBzdHlsZSBvZiB3dXhpYSBmaWxtcyBlbXBoYXNpemluZyBtYWxlIGFudGktaGVyb2VzLCB2aW9sZW50IHN3b3JkcGxheSBhbmQgaGVhdnkgYmxvb2RsZXR0aW5nLiBJdCB3YXMgdGhlIGZpcnN0IEhvbmcgS29uZyBmaWxtIHRvIG1ha2UgSEskMSBtaWxsaW9uIGF0IHRoZSBsb2NhbCBib3ggb2ZmaWNlLCBwcm9wZWxsaW5nIGl0cyBzdGFyIEppbW15IFdhbmcgdG8gc3VwZXIgc3RhcmRvbS4KCld1eGlhIEZpbG1zLiAKClszMCBFc3NlbnRpYWwgV3V4aWEgRmlsbXNdKGh0dHBzOi8vdGhlZW5kb2ZjaW5lbWEubmV0LzIwMTYvMDIvMTEvMzAtZXNzZW50aWFsLXd1eGlhLWZpbG1zLykKCj4gVGhlIENoaW5lc2UgbWFydGlhbCBhcnRzIG1vdmllIGlzIGdlbmVyYWxseSBzcGxpdCBpbnRvIHR3byBwcmltYXJ5IHN1YmdlbmVyZXM6IHRoZSBrdW5nIGZ1IGZpbG0gYW5kIHRoZSB3dXhpYSBmaWxtLiBUaGUga3VuZyBmdSBmaWxtIGlzIG5ld2VyIGFuZCBmb2N1c2VzIHByaW1hcmlseSBvbiBoYW5kLXRvLWhhbmQgY29tYmF0LCBpdOKAmXMgc3RlZXBlZCBpbiB0cmFkaXRpb25hbCBmaWdodGluZyBmb3JtcyBhbmQgdGhlcmXigJlzIGEgZ2VuZXJhbCBlbXBoYXNpcyBvbiB0aGUgcGh5c2ljYWwgc2tpbGwgb2YgdGhlIHBlcmZvcm1lcjogc3BlY2lhbCBlZmZlY3RzIGFyZSBnZW5lcmFsbHkgZGlzZGFpbmVkLiBCcnVjZSBMZWUgYW5kIEphY2tpZSBDaGFuIGFyZSBpdHMgbW9zdCBmYW1vdXMgcHJhY3RpdGlvbmVycyBhbmQgTGF1IEthci1sZXVuZyBpdHMgbW9zdCBpbXBvcnRhbnQgZGlyZWN0b3IuCgo+IFd1eGlhIGlzIGEgbXVjaCBvbGRlciBmb3JtLCBiYXNlZCB1bHRpbWF0ZWx5IGluIHRoZSBsb25nIHRyYWRpdGlvbiBvZiBDaGluZXNlIGFkdmVudHVyZSBsaXRlcmF0dXJlLCBpbiBjbGFzc2ljIG5vdmVscyBzdWNoIGFzIFRoZSBXYXRlciBNYXJnaW4gb3IgSm91cm5leSB0byB0aGUgV2VzdCwgb3IgbW9yZSBjb250ZW1wb3Jhcnkgd29ya3MgYnkgYXV0aG9ycyBsaWtlIExvdWlzIENoYSBhbmQgR3UgTG9uZy4gSXRzIGhlcm9lcyBmb2xsb3cgYSB2ZXJ5IHNwZWNpZmljIGNvZGUgb2YgaG9ub3IgYXMgdGhleSBuYXZpZ2F0ZSB0aGUgamlhbmdodSwgYW4gdW5kZXJ3b3JsZCBvZiBvdXRsYXdzIGFuZCBiYW5kaXRzIG91dHNpZGUgdGhlIG5vcm1hbCBzdHJlYW1zIG9mIGNpdmlsaXphdGlvbi4KCgpGcm9tIFtXdXhpYSBXb21lbiBXYXJyaW9yc10oaHR0cDovL3d3dy5pbmRpZXdpcmUuY29tLzIwMTUvMTAvOC1leHRyYW9yZGluYXJ5LXd1eGlhLWZpbG1zLXBvd2VyZWQtYnktd2Fycmlvci13b21lbi01NjUyNy8pCgo+IExlc3MgcmVhbGlzdGljIHRoYW4gaXRzIGNvdXNpbiwgdGhlIGt1bmcgZnUgZmlsbSwgd3V4aWEgb2Z0ZW4gaW5jbHVkZXMgZ3Jhdml0eS1kZWZ5aW5nIHN0dW50cyB3aGVyZSBsZWdlbmRhcnkgd2FycmlvcnMgZmx5IHRocm91Z2ggdGhlIGFpciBvciBwdW5jaCBob2xlcyBzdHJhaWdodCB0aHJvdWdoIHRoZWlyIGVuZW1pZXPigJkgY2hlc3RzLgoKKipTaGFvbGluIFRpdGxlcyoqCgpgYGB7cn0KdGl0bGVzICU+JSBmaWx0ZXIod29yZCA9PSAnc2hhb2xpbicpICU+JSBhcnJhbmdlKHllYXIpICU+JSBzZWxlY3QocmF3X3RpdGxlLCB5ZWFyKQpgYGAKCgpGcm9tIFtIaXN0b3J5IGluIHRoZSBTaGF3IEJyb3RoZXJzXShodHRwOi8vdGhldnVsZ2FyY2luZW1hLmNvbS8yMDE1LzEyL2hpc3RvcnktaW4tdGhlLXNoYXctYnJvdGhlcnMvKQoKPiBUaGVzZSBmaWxtcywgZm9jdXNlZCBvbiB0aGUgU2hhb2xpbiBUZW1wbGUgYXMgYSBjZW50ZXIgZm9yIGFudGktUWluZyByZXNpc3RhbmNlLCBwcm92aWRlIGEgZGl6enlpbmcgbWV0YXBob3JpY2FsIHBvdGVudGlhbCwgd2l0aCB0aGUgUWluZyB2YXJpb3VzbHkgc3RhbmRpbmcgaW4gZm9yIFdlc3Rlcm4gaW1wZXJpYWxpc3RzLCB0aGUgSmFwYW5lc2UsIHRoZSBOYXRpb25hbGlzdCBLdW9taW5ndGFuZywgdGhlIENvbW11bmlzdHMsIG9yIGV2ZW4gc2ltcGx5IHRoZSBNYW5jaHVyaWFucyB0aGVtc2VsdmVzLCB3aGlsZSB0aGUgQnVkZGhpc20gb2YgdGhlIG1vbmtzIGFsbG93cyBmb3IgZXhhbWluaW5nIG9mIHRoZSBjb250cmFkaWN0aW9ucyBhdCB0aGUgaGVhcnQgb2YgdHJhZGl0aW9uYWwgQ2hpbmVzZSBiZWxpZWYgc3lzdGVtcywgYmV0d2VlbiB0aGUgaW1wZXJhdGl2ZXMgb2Ygc29jaWFsIGp1c3RpY2UgYW5kIHdpdGhkcmF3YWwgZnJvbSB3b3JsZGx5IGNvbmNlcm5zLgoKIyMgRmluZGluZyBBIE1vYiBvZiBWZW5vbXMgCgpbVmVub20gTW9iXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9WZW5vbV9Nb2IpCgpJbnNwaXJhdGlvbiBmcm9tIFtMb3ZlIEFjdHVhbGx5IEFuYWx5c2lzXShodHRwOi8vdmFyaWFuY2VleHBsYWluZWQub3JnL3IvbG92ZS1hY3R1YWxseS1uZXR3b3JrLykgYnkgRGF2aWQgUm9iaW5zb24uCgpDcmVhdGUgYSBtYXRyaXggb2YgYWN0b3IgY28tb2NjdXJhbmNlLgoKYGBge3J9CnN1bW1hcnkoYnlfYWN0b3IkbikKYGBgCgoKYGBge3J9CmxpYnJhcnkocmVzaGFwZTIpCgojIGZpbHRlciBhY3RvcnMgbm90IGluIG1hbnkgbW92aWVzCm1pbl9tb3ZpZV9hY3RvcnMgPC0gYnlfYWN0b3IgJT4lIGZpbHRlcihuID4gNSkKcG9wdWxhcl9jYXN0IDwtIGNhc3QgJT4lIGZpbHRlcihuYW1lICVpbiUgbWluX21vdmllX2FjdG9ycyRuYW1lKSAKCmNhc3RfbW92aWVfbWF0cml4IDwtIHBvcHVsYXJfY2FzdCAlPiUKICBhY2FzdChuYW1lIH4gdGl0bGUsICBmdW4uYWdncmVnYXRlID0gbGVuZ3RoKQpkaW0oY2FzdF9tb3ZpZV9tYXRyaXgpCmBgYAoKUm93cyBhcmUgYWN0b3JzLiBDb2x1bW5zIGFyZSBtb3ZpZXMuIAoKCkZpbHRlciBvdXQgbW92aWVzIHdpdGggZmV3IGNvLW9jY3VyaW5nIGFjdG9ycwoKYGBge3J9CmNhc3RfbW92aWVfZGZfZmlsdGVyZWQgPC0gY2FzdF9tb3ZpZV9kZiAlPiUgY29sU3VtcyguKQpgYGAKCgpgYGB7cn0Kbm9ybSA8LSBjYXN0X21vdmllX21hdHJpeCAvIHJvd1N1bXMoY2FzdF9tb3ZpZV9tYXRyaXgpCgpoY19ub3JtX2Nhc3QgPC0gaGNsdXN0KGRpc3Qobm9ybSwgbWV0aG9kID0gIm1hbmhhdHRhbiIpKQoKYGBgCgoKUGxvdDoKCmBgYHtyLCBmaWcuaGVpZ2h0PTQuOCwgZmlnLndpZHRoPTMuNn0KbGlicmFyeShnZ2RlbmRybykKCmdnZGVuZHJvZ3JhbShoY19ub3JtX2Nhc3QsIHJvdGF0ZSA9IFRSVUUpCmBgYAoKU2VlIG9yZGVyaW5nOgoKYGBge3J9Cm9yZGVyaW5nIDwtaGNfbm9ybV9jYXN0JGxhYmVsc1toY19ub3JtX2Nhc3Qkb3JkZXJdCm9yZGVyaW5nCmBgYAoKYGBge3J9Cm9yZGVyZWRfZmlsbXMgPC0gcG9wdWxhcl9jYXN0ICU+JSBhcnJhbmdlKHllYXIpICU+JQogIG11dGF0ZShmaWxtX2luZGV4ID0gYXMubnVtZXJpYyhmY3RfaW5vcmRlcihmYWN0b3IodGl0bGUpKSksIGNhc3RfbmFtZSA9IGZhY3RvcihuYW1lLCBsZXZlbHMgPSBvcmRlcmluZykpCgpvcmRlcmVkX2ZpbG1zICU+JSBnZ3Bsb3QoYWVzKGZpbG1faW5kZXgsIGNhc3RfbmFtZSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX3BhdGgoYWVzKGdyb3VwID0gZmlsbV9pbmRleCkpCmBgYAoKCmBgYHtyfQojIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTMyODEzMDMvY3JlYXRpbmctY28tb2NjdXJyZW5jZS1tYXRyaXgKY29vY2N1ciA8LSBjYXN0X21vdmllX21hdHJpeCAlKiUgdChjYXN0X21vdmllX21hdHJpeCkKCmRpYWcoY29vY2N1cikgPC0gMAoKaGVhdG1hcChjb29jY3VyLCBzeW1tID0gVFJVRSApCmBgYAoKY29vY2N1ciBpcyBtYXRyaXggd2l0aCByb3dzIGFuZCBjb2x1bW5zIGFzIGFjdG9ycy4gVGhlIGNlbGxzIGZvciBlYWNoIGFjdG9yIGNvbWJvIGluZGljYXRlIHRoZSBudW1iZXIgb2YgbW92aWVzIHRoZXkgaGF2ZSBhcHBlYXJlZCB0b2dldGhlciBpbi4KCmBgYHtyfQpzdW1tYXJ5KHJvd1N1bXMoY29vY2N1cikpCgpzdW1tYXJ5KGNvbFN1bXMoY29vY2N1cikpCgpzdW1tYXJ5KGNvbFN1bXMoY29vY2N1ciAhPSAwKSkKCmNvbGxhYl9jb3VudHMgPC0gYXMuZGF0YS5mcmFtZShjb2xTdW1zKGNvb2NjdXIgIT0gMCkpCmBgYAoKYGBge3J9CmxpYnJhcnkoaWdyYXBoKQoKY29vY2N1ciA8LSBjYXN0X21vdmllX21hdHJpeCAlKiUgdChjYXN0X21vdmllX21hdHJpeCkKI2Nvb2NjdXIgPC0gaWZlbHNlKGNvb2NjdXIgPCA0LCAwLCBjb29jY3VyKQoKZyA8LSBncmFwaC5hZGphY2VuY3koY29vY2N1ciwgd2VpZ2h0ZWQgPSBUUlVFLCBtb2RlID0gInVuZGlyZWN0ZWQiLCBkaWFnID0gRkFMU0UpCgpzdW1tYXJ5KEUoZykkd2VpZ2h0KQoKc3VtbWFyeShkZWdyZWUoZykpCgpzdW1tYXJ5KHN0cmVuZ3RoKGcpKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NH0KbGlicmFyeShpZ3JhcGgpCgpjb29jY3VyIDwtIGNhc3RfbW92aWVfbWF0cml4ICUqJSB0KGNhc3RfbW92aWVfbWF0cml4KQojY29vY2N1ciA8LSBpZmVsc2UoY29vY2N1ciA8IDQsIDAsIGNvb2NjdXIpCgpnIDwtIGdyYXBoLmFkamFjZW5jeShjb29jY3VyLCB3ZWlnaHRlZCA9IFRSVUUsIG1vZGUgPSAidW5kaXJlY3RlZCIsIGRpYWcgPSBGQUxTRSkKCmxvd19kZWdyZWVfdiA8LSBWKGcpW2RlZ3JlZShnKSA8IDEwXSAjaWRlbnRpZnkgdGhvc2UgdmVydGljZXMgcGFydCBvZiBsZXNzIHRoYW4gdGhyZWUgZWRnZXMKZyA8LSBkZWxldGVfdmVydGljZXMoZywgbG93X2RlZ3JlZV92KSAjZXhjbHVkZSB0aGVtIGZyb20gdGhlIGdyYXBoCgpsb3dfd2VpZ2h0X2UgPC0gRShnKVtFKGcpJHdlaWdodCA8IDNdCmcgPC0gZGVsZXRlX2VkZ2VzKGcsIGxvd193ZWlnaHRfZSkKCmxvd19zdHJlbmd0aF92IDwtIFYoZylbc3RyZW5ndGgoZykgPCA5MF0KZyA8LSBkZWxldGVfdmVydGljZXMoZywgbG93X3N0cmVuZ3RoX3YpICNleGNsdWRlIHRoZW0gZnJvbSB0aGUgZ3JhcGgKClYoZykkYmV0d2Vlbm5lc3MgPC0gc3RyZW5ndGgoZykKCnBsb3QoZywgZWRnZS53aWR0aCA9IEUoZykkd2VpZ2h0LCAKICAgICAjbGF5b3V0PWxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZCwKICAgICBsYXlvdXQ9bGF5b3V0X3dpdGhfZnIsCiAgICAgdmVydGV4LmxhYmVsLmRpc3Q9MC41LAogICAgICN2ZXJ0ZXguc2l6ZSA9IFYoZykkYmV0d2Vlbm5lc3MsCiAgICAgdmVydGV4LnNpemUgPSAzLAogICAgIHZlcnRleC5jb2xvcj0nc3RlZWxibHVlJywKICAgICB2ZXJ0ZXguZnJhbWUuY29sb3I9J3N0ZWVsYmx1ZScsIAkJI3RoZSBjb2xvciBvZiB0aGUgYm9yZGVyIG9mIHRoZSBkb3RzIAogICAgIHZlcnRleC5sYWJlbC5jb2xvcj0nYmxhY2snLAkJI3RoZSBjb2xvciBvZiB0aGUgbmFtZSBsYWJlbHMKICAgICB2ZXJ0ZXgubGFiZWwuZm9udD0yLAkJCSN0aGUgZm9udCBvZiB0aGUgbmFtZSBsYWJlbHMKICAgICB2ZXJ0ZXgubGFiZWwuY2V4PTEsCQkJI3NwZWNpZmllcyB0aGUgc2l6ZSBvZiB0aGUgZm9udCBvZiB0aGUgbGFiZWxzLiBjYW4gYWxzbyBiZSBtYWRlIHRvIHZhcnkKICAgICBlZGdlLmNvbG9yID0gaHN2KDEsMSwxLGFscGhhPTAuMikKCikKYGBgCgoKYGBge3J9CmNoaWFuZ19zaGVuZyA8LSBWKGcpW1YoZykkbmFtZSA9PSAiQ2hpYW5nIFNoZW5nIl0KCmNoaWFuZ19zaGVuZ19uZWlnaGJvcnMgPC0gbmVpZ2hib3JzKGcsIGNoaWFuZ19zaGVuZykKbmVpZ2hib3JfZWRnZXMgPC0gaW5jaWRlbnRfZWRnZXMoZywgY2hpYW5nX3NoZW5nX25laWdoYm9ycykKCnN1Yl9nIDwtIG1ha2VfZW1wdHlfZ3JhcGgobiA9IGxlbmd0aChjaGlhbmdfc2hlbmdfbmVpZ2hib3JzKSwgZGlyZWN0ZWQgPSBGQUxTRSkKYWRkX3ZlcnRpY2VzKHN1Yl9nLCBjaGlhbmdfc2hlbmdfbmVpZ2hib3JzKQoKI2FkZF9lZGdlcyhzdWJfZywgbmVpZ2hib3JfZWRnZXMpCkUoZylbbmVpZ2hib3JfZWRnZXMkY29sb3IgPSBoc3YoMCwwLjIsMC41LGFscGhhPTAuNSkKVihnKSRjb2xvciA9ICJncmV5IgpWKGcpW2NoaWFuZ19zaGVuZ10kY29sb3IgPSAidG9tYXRvIgpWKGcpW2NoaWFuZ19zaGVuZ19uZWlnaGJvcnNdJGNvbG9yID0gJ3RvbWF0bycKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NH0KcGxvdChnLCBlZGdlLndpZHRoID0gRShnKSR3ZWlnaHQsIAogICAgICNsYXlvdXQ9bGF5b3V0LmZydWNodGVybWFuLnJlaW5nb2xkLAogICAgIGxheW91dD1sYXlvdXRfd2l0aF9mciwKICAgICB2ZXJ0ZXgubGFiZWwuZGlzdD0wLjUsCiAgICAgI3ZlcnRleC5zaXplID0gVihnKSRiZXR3ZWVubmVzcywKICAgICB2ZXJ0ZXguc2l6ZSA9IDUsCiAgICAgdmVydGV4LmNvbG9yPVYoZykkY29sb3IsCiAgICAgdmVydGV4LmZyYW1lLmNvbG9yPSdzdGVlbGJsdWUnLCAJCSN0aGUgY29sb3Igb2YgdGhlIGJvcmRlciBvZiB0aGUgZG90cyAKICAgICB2ZXJ0ZXgubGFiZWwuY29sb3I9J2JsYWNrJywJCSN0aGUgY29sb3Igb2YgdGhlIG5hbWUgbGFiZWxzCiAgICAgdmVydGV4LmxhYmVsLmZvbnQ9MiwJCQkjdGhlIGZvbnQgb2YgdGhlIG5hbWUgbGFiZWxzCiAgICAgdmVydGV4LmxhYmVsLmNleD0xLAkJCSNzcGVjaWZpZXMgdGhlIHNpemUgb2YgdGhlIGZvbnQgb2YgdGhlIGxhYmVscy4gY2FuIGFsc28gYmUgbWFkZSB0byB2YXJ5CiAgICAgZWRnZS5jb2xvciA9IGhzdigwLDAuMiwwLjUsYWxwaGE9MC4yKQopCmBgYAoKCmBgYHtyfQpjb29jY3VyX2RmIDwtIGRhdGEuZnJhbWUoY29vY2N1ciwgY29sLm5hbWVzID0gY29sbmFtZXMoY29vY2N1cikpCmNvb2NjdXJfZGYkbmFtZSA8LSByb3cubmFtZXMoY29vY2N1cikgCmNvb2NjdXJfZGYgPC0gY29vY2N1cl9kZiAlPiUgc2VsZWN0KG5hbWUsIGV2ZXJ5dGhpbmcoKSkKd3JpdGVfZGVsaW0oY29vY2N1cl9kZiwgJ3NoYXdfY29vY2N1cmFuY2UuY3N2JywgZGVsaW0gPSAnOycpCmBgYAoKYGBge3J9CgpgYGAKCgoKIyMgT3RoZXIKCiMjIFIgTWFya2Rvd24gTm90ZXMKClRoaXMgaXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rLiBXaGVuIHlvdSBleGVjdXRlIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuIAoKVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkNtZCtTaGlmdCtFbnRlciouIAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLgo=